package com.example.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.example.gateway.config.CommonConstants;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.org.vo.ResultEntity;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

/**
 * @date 2018/7/4
 * 验证码处理
 */
@Slf4j
@Component
@AllArgsConstructor
public class ValidateCodeGatewayFilter extends AbstractGatewayFilterFactory {
   private final ObjectMapper objectMapper;

   private final RedisTemplate redisTemplate;

   @Override
   public GatewayFilter apply(Object config) {
      return (exchange, chain) -> {
         ServerHttpRequest request = exchange.getRequest();

         // 不是登录请求，直接向下执行
         log.info("gateway ValidateCodeGatewayFilter 过滤器 请求的地址为:{}", request.getURI().getPath());
         if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath()
                 , CommonConstants.OAUTH_TOKEN_URL)) {
            return chain.filter(exchange);
         }
         // 终端设置不校验， 直接向下执行
         try {
            //校验验证码
            checkCode(request);
         } catch (Exception e) {
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
            try {
               return response.writeWith(Mono.just(response.bufferFactory()
                       .wrap(objectMapper.writeValueAsBytes(ResultEntity.error(e.getMessage(), null)))));
            } catch (JsonProcessingException e1) {
               log.error("对象输出异常", e1);
            }
         }

         return chain.filter(exchange);
      };
   }


   /**
    * 检查code
    *
    * @param request
    */
   @SneakyThrows
   private void checkCode(ServerHttpRequest request) {
      String code = request.getQueryParams().getFirst("code");

      if (StrUtil.isBlank(code)) {
         throw new Exception("验证码不能为空");
      }

      String randomStr = request.getQueryParams().getFirst("randomStr");
      if (StrUtil.isBlank(randomStr)) {
         throw new Exception("随机数不能为空");
      }

      String key = CommonConstants.DEFAULT_CODE_KEY + randomStr;
      if (!redisTemplate.hasKey(key)) {
         throw new Exception("验证码不合法");
      }

      Object codeObj = redisTemplate.opsForValue().get(key);

      if (codeObj == null) {
         throw new Exception("验证码不合法");
      }

      String saveCode = codeObj.toString();
      if (StrUtil.isBlank(saveCode)) {
         redisTemplate.delete(key);
         throw new Exception("验证码不合法");
      }

      if (!StrUtil.equals(saveCode, code)) {
         redisTemplate.delete(key);
         throw new Exception("验证码不合法");
      }
      redisTemplate.delete(key);
   }
}